#include <EB0/EB0.h>

// Keep in mind that coordinates are based on a top-left (0,0) system
// The closer to the bottom of the screen the higher the y-value

namespace EB0
{
namespace Graphics
{
#pragma region Renderable Compare (used by Layer)
	// Determine the drawing order for renderable objects. Return true if drawn before the other, false if after.
	// Our goal is to have objects with an ascending z (index), ascending y, descending x drawing order.
	// Higher z-index objects are to be drawn later. Otherwise lower y and higher x objects are drawn later.
	bool Renderable::compare(const Renderable& lhs, const Renderable& rhs)
	{
		// Lower z-index?
		if (lhs.z < rhs.z)
			return true;
		else if (FLOAT_EQ(lhs.z, rhs.z))
		{
			// Lower y value? (0,0) represents the top left corner of the screen. Lower y = higher up screen than the other.
			if (lhs.GetPosition().y < rhs.GetPosition().y)
				return true;
			else if (FLOAT_EQ(lhs.GetPosition().y, rhs.GetPosition().y))
			{
				// Higher x value? We'll also accept an equal x-value.
				if (lhs.GetPosition().x > rhs.GetPosition().x || FLOAT_EQ(lhs.GetPosition().x, rhs.GetPosition().x))
					return true;
			}
		}

		// Draw the first object after the second
		return false;
	}

	// Compare given two pointers
	bool Renderable::comparePtr(const Renderable* lhs, const Renderable* rhs)
	{
		// Check if pointers are valid
		if (!lhs)
			return true; // Place the first object before the second

		if (!rhs)
			return false; // Place the second object before the first

		return compare(*lhs, *rhs);
	}
#pragma endregion

#pragma region Constructor / Destructor
	// Default Constructor
	Renderable::Renderable(float zindex)
	{
		mDrawable = 0;
		z = zindex;
	}

	// Constructor with sf::Drawable*
	Renderable::Renderable(sf::Drawable* drawable, float zindex)
	{
		mDrawable = drawable;
		z = zindex;
	}

	// Destructor
	Renderable::~Renderable()
	{
		mDrawable = 0;
		z = 0.0f;
	}
#pragma endregion

#pragma region Manage Drawable
	// Set drawable
	void Renderable::setDrawable(sf::Drawable* drawable)
	{
		mDrawable = drawable;
	}

	// Get drawable
	sf::Drawable* Renderable::getDrawable() const
	{
		return mDrawable;
	}

	// Remove drawable
	void Renderable::removeDrawable()
	{
		mDrawable = 0;
	}
#pragma endregion

#pragma region In View
	// A simple function used to cull the object from rendering.
	// True = in view; False = not in view, no need to draw.
	bool Renderable::inView(sf::View& view) const
	{
		// By default always draw the object
		return true;
	}
#pragma endregion

#pragma region Rendering
	// 'Render' method used by sf::Drawable and called through the RenderWindow
	void Renderable::Render(sf::RenderTarget& Target) const
	{
		// Render the sf::Drawable object
		if (mDrawable)
			Target.Draw(*mDrawable);
	}
#pragma endregion
} // namespace Graphics
}